package shopping

import (
	"time"
	"strconv"
	"encoding/json"
	"dhfshop/models/misc"
	"dhfshop/models/sale"
	"dhfshop/models/shopping"
	"dhfshop/models/im"
	"dhfshop/models/member"
	"dhfshop/utils/math"
	"dhfshop/service/redisgo"
	"dhfshop/controllers/base"
	"dhfshop/models/consts"
	"github.com/astaxie/beego"
	"github.com/pkg/errors"
	"github.com/astaxie/beego/validation"
)

/*
备注1：
顾客，每参加1次砍价，需要根据规则，计算出来： 砍多少钱，
同时更新到：砍价活动表BargainActivity，累加砍价次数，和砍掉的总金额。

备注2：
规则是商家创建的，保存一条rule
顾客发起砍价活动，存储一条 activity
别的顾客帮助砍价，存储一条 detail
*/


// 砍价活动管理
type BargainController struct {
	base.BaseController
}

func (this *BargainController) RuleList() {
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	l, cnt, err := shopping.GetAllBargainRules(query,fields,order_by,offset,limit)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		TotalCount   int64                   `json:"total_count"`
		BargainRules []*shopping.BargainRule `json:"bargain_rules"`
	}{TotalCount: cnt, BargainRules: l}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) RulePost() {
	var v shopping.BargainRule
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.Title, "title")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	v.PartnerId = int64(this.Ctx.Input.GetData("curCompanyId").(int))
	if len(v.ItemIdStr) > 0 {
		v.ItemId, _= strconv.ParseInt(v.ItemIdStr, 10, 64)
	}
	if len(v.SkuIdStr) > 0 {
		v.SkuId, _= strconv.ParseInt(v.SkuIdStr, 10, 64)
	}
	if len(v.StartTimeStr) > 0 {
		v.StartTime, _ = time.Parse(consts.DATETIME_FORMAT,v.StartTimeStr)
	}
	if len(v.EndTimeStr) > 0 {
		v.EndTime, _ = time.Parse(consts.DATETIME_FORMAT,v.EndTimeStr)
	}
	_, err := shopping.AddBargainRule(&v)
	if err != nil {
	   this.ServeError(err.Error())
		return 
	}
	rsp := struct {
		BargainRuleId int64      `json:"bargain_rule_id"`
	    Created       time.Time  `json:"created"`
	}{BargainRuleId: v.BargainRuleId, Created:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) RulePut() {
	v := shopping.BargainRule{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.BargainRuleId, "bargain_rule_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	v.PartnerId = int64(this.Ctx.Input.GetData("curCompanyId").(int))
	if len(v.ItemIdStr) > 0 {
		v.ItemId, _= strconv.ParseInt(v.ItemIdStr, 10, 64)
	}
	if len(v.SkuIdStr) > 0 {
		v.SkuId, _= strconv.ParseInt(v.SkuIdStr, 10, 64)
	}
	if len(v.StartTimeStr) > 0 {
	    v.StartTime, _ = time.Parse(consts.DATETIME_FORMAT,v.StartTimeStr)
	}
	if len(v.EndTimeStr) > 0 {
	    v.EndTime, _ = time.Parse(consts.DATETIME_FORMAT,v.EndTimeStr)
	}
	excludeArr := []string{""}
	updateFields, err := this.GetUpdateFields(v, "", "form", excludeArr)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	if err := shopping.UpdateBargainRuleById(&v, updateFields...); err != nil{
		this.ServeError(err.Error())
		return
	}
	
	r := struct {
	    BargainRuleId int64    `json:"bargain_rule_id"`
	    Modified   time.Time   `json:"modified"`
	}{BargainRuleId:v.BargainRuleId, Modified:time.Now().UTC()}
	this.Data["json"] = r
	this.ServeJSON()
}

func (this *BargainController) RuleDelete() {
   partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
    //curUserId := this.Ctx.Input.GetData("curUserId").(int)
	v := struct {
		PartnerId      int64    `form:"-"  valid:"Required"`
	    BargainRuleId  int64  `form:"bargain_rule_id" valid:"Required"`
	}{PartnerId: int64(partnerId)} 
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.BargainRuleId, "bargain_rule_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	if err := shopping.DeleteBargainRule(v.PartnerId, v.BargainRuleId); err != nil {
		this.ServeError(err.Error())
		return
	}
	r := struct {
	    BargainRuleId int64     `json:"bargain_rule_id"`
	    Modified      time.Time `json:"modified"`
	}{BargainRuleId:v.BargainRuleId, Modified:time.Now().UTC()}
	this.Data["json"] = r
	this.ServeJSON() 
}
/******************************/
func (this *BargainController) ActivityList() {
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	l, cnt, err := shopping.GetAllBargainActivitys(query,fields,order_by,offset,limit)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		TotalCount       int64                       `json:"total_count"`
		BargainActivitys []*shopping.BargainActivity `json:"bargain_activitys"`
	}{TotalCount: cnt, BargainActivitys: l}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) ActivityPost() {
	var v shopping.BargainActivity
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.BargainRuleId, "bargain_rule_id")
	valid.Required(v.OpenId, "open_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	curAppId := this.Ctx.Input.GetData("curAppId").(string)   //buyer登录，有此参数
	bargainRule, err := shopping.GetBargainRuleById(v.BargainRuleId)
	if err != nil {
	    this.ServeError(err.Error())
		return 
	}
	nowUnix := time.Now().Unix()
	if  nowUnix < bargainRule.StartTime.Unix() {
	    this.ServeError("bargain rule start_time is not start")
		return 
	}
	if  nowUnix > bargainRule.EndTime.Unix() {
	    this.ServeError("bargain rule end_time is expired")
		return 
	}
	v.PartnerId = bargainRule.PartnerId
	_, err = shopping.AddBargainActivity(&v)
	if err != nil {
	   this.ServeError(err.Error())
		return 
	}
	if len(v.FormId) > 0 {
	    formIdCache := &im.FormIdCache{PartnerId:v.PartnerId,MemberId:0,AppId:curAppId,
	                  FormId:v.FormId,OpenId:v.OpenId,Types:"bargain",Xid:strconv.FormatInt(v.BargainRuleId,10),
					  MaxCount:1,ExpireAt:time.Now().UTC().Add(time.Hour*24*7)}
		im.AddFormIdCache(formIdCache)
	}
	rsp := struct {
		BargainActivityId int64      `json:"bargain_activity_id"`
	    Created         time.Time  `json:"created"`
	}{BargainActivityId: v.BargainActivityId, Created:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

/******************************/
func (this *BargainController) DetailList() {
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	l, cnt, err := shopping.GetAllBargainActivityDetails(query,fields,order_by,offset,limit)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		TotalCount             int64                              `json:"total_count"`
		BargainActivityDetails []*shopping.BargainActivityDetails `json:"bargain_details"`
	}{TotalCount: cnt, BargainActivityDetails: l}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) DetailPost() {
	var v shopping.BargainActivityDetails
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.BargainRuleId, "bargain_rule_id")
	valid.Required(v.BargainActivityId, "bargain_activity_id")
	valid.Required(v.OpenId, "open_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	v.PartnerId = int64(this.Ctx.Input.GetData("curCompanyId").(int))
	bargainRule, err := shopping.GetBargainRuleById(v.BargainRuleId)
	if err != nil {
	    err = errors.Wrap(err, "GetBargainRuleById... ")
		this.ServeError(err.Error())
		return
	}
	bargainActivity, err := shopping.GetBargainActivityById(v.BargainActivityId)
	if err != nil {
	    err = errors.Wrap(err, "GetBargainActivityById... ")
	    this.ServeError(err.Error())
		return
	}
	if bargainActivity.IsUsed == 1 {
	    this.ServeError("The current bargaining activities has used")
		return
	}
	//校验当前砍价总数是否超过了规则中设置的最大砍价次数
	if bargainActivity.TotalBargainTimes >= bargainRule.NeedBargainTimes {
	    this.ServeError("The current number of bargaining activities has arrived")
		return
	}
	if bargainRule.CutWay == 2 {
	    remainSize := bargainRule.NeedBargainTimes - bargainActivity.TotalBargainTimes
		remainMoney := math.SubPrice(bargainRule.NeedCutOffFee, bargainActivity.TotalCutOffFee)
		rd := math.GetRandomMoney(remainSize, float64(remainMoney))
		beego.Debug("rule_id,activity_id,remain_size,remain_money,rd:",v.BargainRuleId,v.BargainActivityId,remainSize,remainMoney,rd)
		v.CutOffFee = float32(rd)
	}else {
	    remainSize := bargainRule.NeedBargainTimes - bargainActivity.TotalBargainTimes
		remainMoney := math.SubPrice(bargainRule.NeedCutOffFee, bargainActivity.TotalCutOffFee)
		if remainSize == 1 {
		    v.CutOffFee = remainMoney
		} else {
		    v.CutOffFee = math.DivTotalFee(bargainRule.NeedCutOffFee, bargainRule.NeedBargainTimes)
		}
	}
	_, err = shopping.AddBargainActivityDetails(&v)
	if err != nil {
	    err = errors.Wrap(err, "AddBargainActivityDetails... ")
		this.ServeError(err.Error())
		return 
	}
	bargainActivity.TotalBargainTimes++
	bargainActivity.TotalCutOffFee = bargainActivity.TotalCutOffFee + v.CutOffFee
	if err = shopping.UpdateBargainActivityById(bargainActivity, "total_bargain_times", "total_cut_off_fee");err != nil {
	    this.ServeError(err.Error())
		return
	}
	rsp := struct {
		BargainDetailId int64      `json:"bargain_detail_id"`
	    Created         time.Time  `json:"created"`
	}{BargainDetailId: v.BargainDetailId, Created:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) GetBargainEffect() {
    partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
    //curUserId := this.Ctx.Input.GetData("curUserId").(int)
	v := struct {
		PartnerId      int64    `form:"-"  valid:"Required"`
	    BargainRuleId  int64  `form:"bargain_rule_id" valid:"Required"`
	}{PartnerId: int64(partnerId)} 
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.BargainRuleId, "bargain_rule_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	totalActivitys,totalTimes,totalFees,err := shopping.SumBargainActivitys(v.PartnerId, v.BargainRuleId)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	rsp := struct {
	    BargainRuleId        int64   `json:"bargain_rule_id"`
	    TotalBargainActivity int     `json:"total_bargain_activity"`
		TotalBargainTimes    int     `json:"total_bargain_times"`
		TotalBargainFee      float32 `json:"total_bargain_fee"`
	}{BargainRuleId:v.BargainRuleId,TotalBargainActivity:totalActivitys,TotalBargainTimes:totalTimes,TotalBargainFee:totalFees}
	this.Data["json"] = rsp
	this.ServeJSON() 
}

func (this *BargainController) ItemPackGet() {
	//beego.Debug("ItemPackGet...")
	type ItemPack struct {
		Item         *sale.Item              `json:"items"`
		BargainRules []*shopping.BargainRule `json:"bargain_rules"`
		Pintuans     []*shopping.Pintuan     `json:"pin_tuans"`
	}
	var (
		allowStoreId []int64
		itemIdArr    []string
		itemPackArr  []*ItemPack
	)
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	list, cnt, err := sale.GetAllItems(allowStoreId,query,itemIdArr,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	redisconn := redisgo.GetInstance()
	//
	for _, item := range list {
		itemPack := &ItemPack{}
		itemPack.Item = item
		cacheKey := strconv.FormatInt(item.ItemId, 10)
		if cacheValue, err := redisconn.GetString(cacheKey); err == nil && len(cacheValue) > 0  {
			if tmpPrice, err := strconv.ParseFloat(cacheValue, 32); err == nil {
			   itemPack.Item.PromPrice = float32(tmpPrice)
			}
		}else{
		    if _, promPrice, err := shopping.GetMaxDiscountFee(item.PartnerId,item.StoreId,item.ItemId,0,0,item.Price); err == nil {
			   itemPack.Item.PromPrice = promPrice
			}
			tmpValue := strconv.FormatFloat(float64(itemPack.Item.PromPrice), 'f', -1, 32)
			if _, err = redisconn.Set(cacheKey, tmpValue, 10*60); err != nil {
			   beego.Debug("SETEX", err.Error())
			}
		}
		if tmpBargainRules, err := shopping.GetTimeValidBargainRules(item.ItemId); err == nil {
		   itemPack.BargainRules = tmpBargainRules
		}
		if tmpPinTuan, err := shopping.GetTimeValidPinTuans(item.ItemId); err == nil {
		   itemPack.Pintuans = tmpPinTuan
		}
		itemPackArr = append(itemPackArr, itemPack)
	}
	rsp := struct {
		TotalCount  int64        `json:"total_count"`
		ItemPacks   []*ItemPack  `json:"items_pack"`
	}{TotalCount: cnt, ItemPacks: itemPackArr}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) TokenItemPackGet() {
	//beego.Debug("TokenItemPackGet...")
	var model int = 0
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
    curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	curAppId := this.Ctx.Input.GetData("curAppId").(string)
	type ItemPack struct {
		Item         *sale.Item              `json:"items"`
		BargainRules []*shopping.BargainRule `json:"bargain_rules"`
		Pintuans     []*shopping.Pintuan     `json:"pin_tuans"`
		Activity     *shopping.Activity      `json:"activity"`
		PromPrice    float32                 `json:"prom_price"`
	}
	type ItemCache struct {
		Activity     *shopping.Activity      `json:"activity"`
		PromPrice    float32                 `json:"prom_price"`
	}
	var (
		allowStoreId   []int64
		itemIdArr      []string
		itemPackArr    []*ItemPack          
	)
	query,subQuery,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	if _, ok := query["level"]; ok {
	    model = 1
		delete(query, "level")
	}
	//也支持读取店铺配置
	//beego.Debug("TokenItemPackGet appid:", curAppId)
	if appCfg, err := misc.GetWxAppCfgByAppIdAndName(curAppId, "CONFIG-ShowLevelPrice"); err == nil {
        var dat map[string]int
		var result int
		dat = make(map[string]int)
		//beego.Debug("curAppId:", curAppId, "appCfg.Value:", appCfg.Value)
        err = json.Unmarshal([]byte(appCfg.Value), &dat)
        if err == nil {
		   for _, v := range dat {
			  result = v
		   }
		   if result == 2 {
		      model = 1
		   }
		}
	}else{
	    beego.Debug("GetWxAppCfgByAppIdAndName error:", err.Error())
	}
	if len(subQuery) > 0 {
	    idArr, err := sale.GetItemIdArrBySubQuery(subQuery)
	    if len(idArr) > 0 && err == nil {
	        itemIdArr = idArr
	    }else{
		    itemIdArr = append(itemIdArr, "000000")
		}
	}
	list, cnt, err := sale.GetAllItems(allowStoreId,query,itemIdArr,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	memberValue, err := member.GetMemberById(curUserId)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	for _, item := range list {
		itemPack := &ItemPack{}
		itemPack.Item = item
		if model > 0 {
		    var sku_id int64 = 0
			if _, ok := subQuery["sku_id"]; ok {
			   sku_id, _= strconv.ParseInt(subQuery["sku_id"], 10, 64)
            }
			if actId, promPrice, err := shopping.GetMaxDiscountFeeModel2(partnerId,item.StoreId,item.ItemId,sku_id,memberValue.Level,item.Price); err == nil {
			   itemPack.Item.PromPrice = promPrice
			   if activity, err := shopping.GetActivityById(actId); err == nil {
				   itemPack.Activity = activity
			   }
			}else{
			   itemPack.Item.PromPrice = 0
			}
		}else{
		    var sku_id int64 = 0
			if _, ok := subQuery["sku_id"]; ok {
			   sku_id, _= strconv.ParseInt(subQuery["sku_id"], 10, 64)
            }
			if actId, promPrice, err := shopping.GetMaxDiscountFee(partnerId,item.StoreId,item.ItemId,sku_id,memberValue.Level,item.Price); err == nil {
			   itemPack.Item.PromPrice = promPrice
			   if activity, err := shopping.GetActivityById(actId); err == nil {
				   itemPack.Activity = activity
			   }
			}else{
			   itemPack.Item.PromPrice = 0
			}
		}
		if tmpBargainRules, err := shopping.GetTimeValidBargainRules(item.ItemId); err == nil {
		   itemPack.BargainRules = tmpBargainRules
		}
		if tmpPinTuan, err := shopping.GetTimeValidPinTuans(item.ItemId); err == nil {
		   itemPack.Pintuans = tmpPinTuan
		}
		itemPackArr = append(itemPackArr, itemPack)
	}
	rsp := struct {
		TotalCount  int64        `json:"total_count"`
		ItemPacks   []*ItemPack  `json:"items_pack"`
	}{TotalCount: cnt, ItemPacks: itemPackArr}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *BargainController) ItemPackTagIdsGet() {
	//beego.Debug("ItemPackTagIdsGet...")
	var model int = 0
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
    curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	curAppId := this.Ctx.Input.GetData("curAppId").(string)
	type ItemPack struct {
		Item         *sale.Item              `json:"items"`
		BargainRules []*shopping.BargainRule `json:"bargain_rules"`
		Pintuans     []*shopping.Pintuan     `json:"pin_tuans"`
		Activity     *shopping.Activity      `json:"activity"`
		PromPrice    float32                 `json:"prom_price"`
	}
	var (
		itemPackArr    []*ItemPack          
	)
	v := struct {
	    TagId      string  `form:"tag_id" valid:"Required"`
		CategoryId string  `form:"category_id"`
		ItemId     string  `form:"item_id"`
		OnShelves  int     `form:"on_shelves"`
		SaleNum    string  `form:"sale_num"`
		Price      string  `form:"price"`
		PageSize   int     `form:"page_size"`
		PageNo     int     `form:"page_no"`
	}{PageSize:10, PageNo:1}     
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Range(v.PageSize,1,1000,"page_size")
	valid.Range(v.PageNo,1,1000,"page_no")
	passed, _ := valid.Valid(&v)
	if !passed {
		err := errors.New(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		this.ServeError(err.Error())
	}
	if appCfg, err := misc.GetWxAppCfgByAppIdAndName(curAppId, "CONFIG-ShowLevelPrice"); err == nil {
        var dat map[string]int
		var result int
		dat = make(map[string]int)
		//beego.Debug("curAppId:", curAppId, "appCfg.Value:", appCfg.Value)
        err = json.Unmarshal([]byte(appCfg.Value), &dat)
        if err == nil {
		   for _, v := range dat {
			  result = v
		   }
		   if result == 2 {
		      model = 1
		   }
		}
	}else{
	    beego.Debug("GetWxAppCfgByAppIdAndName error:", err.Error())
	}
	v.PageNo = v.PageNo - 1     //为了计算offset
	offset := v.PageNo*v.PageSize
	limit := v.PageSize
	cnt, list, err := sale.GetItemsByTagIds(v.CategoryId,v.ItemId,v.TagId,v.SaleNum,v.Price,v.OnShelves,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	memberValue, err := member.GetMemberById(curUserId)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	for _, item := range list {
		itemPack := &ItemPack{}
		item.ItemIdStr = strconv.FormatInt(item.ItemId, 10)
		itemPack.Item = item
        if model > 0 {
		    if actId, promPrice, err := shopping.GetMaxDiscountFeeModel2(partnerId,item.StoreId,item.ItemId,0,memberValue.Level,item.Price); err == nil {
			   itemPack.Item.PromPrice = promPrice
			   if activity, err := shopping.GetActivityById(actId); err == nil {
				   itemPack.Activity = activity
			   }
			}else{
			   itemPack.Item.PromPrice = 0
			}
		}else{
		    if actId, promPrice, err := shopping.GetMaxDiscountFee(partnerId,item.StoreId,item.ItemId,0,memberValue.Level,item.Price); err == nil {
			   itemPack.Item.PromPrice = promPrice
			   if activity, err := shopping.GetActivityById(actId); err == nil {
				   itemPack.Activity = activity
			   }
			}else{
			   itemPack.Item.PromPrice = 0
			}
		}
		if tmpBargainRules, err := shopping.GetTimeValidBargainRules(item.ItemId); err == nil {
		   itemPack.BargainRules = tmpBargainRules
		}
		if tmpPinTuan, err := shopping.GetTimeValidPinTuans(item.ItemId); err == nil {
		   itemPack.Pintuans = tmpPinTuan
		}
		itemPackArr = append(itemPackArr, itemPack)
	}
	rsp := struct {
		TotalCount  int64        `json:"total_count"`
		ItemPacks   []*ItemPack  `json:"items_pack"`
	}{TotalCount: cnt, ItemPacks: itemPackArr}
	this.Data["json"] = rsp
	this.ServeJSON()
}
